package www.ivan.uvccamerademo;

import android.annotation.SuppressLint;
import android.content.Intent;
import android.graphics.SurfaceTexture;
import android.hardware.usb.UsbDevice;
import android.os.Bundle;
import android.util.Log;
import android.view.Surface;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Toast;

import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.List;

import com.serenegiant.common.BaseActivity;
import com.serenegiant.usb.CameraDialog;
import com.serenegiant.usb.CameraDialog.CameraDialogParent;
import com.serenegiant.usb.IButtonCallback;
import com.serenegiant.usb.IFrameCallback;
import com.serenegiant.usb.IStatusCallback;
import com.serenegiant.usb.USBMonitor;
import com.serenegiant.usb.USBMonitor.OnDeviceConnectListener;
import com.serenegiant.usb.USBMonitor.UsbControlBlock;
import com.serenegiant.usb.UVCCamera;
import serenegiant.widget.SimpleUVCCameraTextureView;

public  class MainActivity extends BaseActivity implements CameraDialogParent {
    private static final boolean DEBUG = false;    // FIXME set false when production
    private static final String TAG = "MainActivity";

    // for accessing USB and USB camera
    private USBMonitor mUSBMonitor;


    private SimpleUVCCameraTextureView mUVCCameraView1, mUVCCameraView2, mUVCCameraView3, mUVCCameraView4, mUVCCameraView5, mUVCCameraView6;
    private UVCCamera mUVCCamera1, mUVCCamera2, mUVCCamera3, mUVCCamera4, mUVCCamera5, mUVCCamera6;
    private final Object mSync = new Object();
    //	private final Object mSyncR = new Object();
    private Toast mToast;
    private Surface mPreviewSurface1, mPreviewSurface2, mPreviewSurface3, mPreviewSurface4, mPreviewSurface5, mPreviewSurface6;
    /**
     * 从1到6
     */
    private int type = 1;

    private List<String> list = new ArrayList<>();


    @Override
    protected void onCreate(final Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        findViewById(R.id.RelativeLayout1).setOnClickListener(mOnClickListener);

        mUVCCameraView1 =  findViewById(R.id.camera_view_1);
        mUVCCameraView2 =  findViewById(R.id.camera_view_2);
        mUVCCameraView3 =  findViewById(R.id.camera_view_3);
        mUVCCameraView4 =  findViewById(R.id.camera_view_4);
        mUVCCameraView5 =  findViewById(R.id.camera_view_5);
        mUVCCameraView6 =  findViewById(R.id.camera_view_6);

        // 保持视图按比例显示
        mUVCCameraView1.setAspectRatio(UVCCamera.DEFAULT_PREVIEW_WIDTH / (float) UVCCamera.DEFAULT_PREVIEW_HEIGHT);
        mUVCCameraView2.setAspectRatio(UVCCamera.DEFAULT_PREVIEW_WIDTH / (float) UVCCamera.DEFAULT_PREVIEW_HEIGHT);
        mUVCCameraView3.setAspectRatio(UVCCamera.DEFAULT_PREVIEW_WIDTH / (float) UVCCamera.DEFAULT_PREVIEW_HEIGHT);
        mUVCCameraView4.setAspectRatio(UVCCamera.DEFAULT_PREVIEW_WIDTH / (float) UVCCamera.DEFAULT_PREVIEW_HEIGHT);
        mUVCCameraView5.setAspectRatio(UVCCamera.DEFAULT_PREVIEW_WIDTH / (float) UVCCamera.DEFAULT_PREVIEW_HEIGHT);
        mUVCCameraView6.setAspectRatio(UVCCamera.DEFAULT_PREVIEW_WIDTH / (float) UVCCamera.DEFAULT_PREVIEW_HEIGHT);

        mUVCCameraView1.setOnClickListener(mOnClickListener);
        mUVCCameraView2.setOnClickListener(mOnClickListener);
        mUVCCameraView3.setOnClickListener(mOnClickListener);
        mUVCCameraView4.setOnClickListener(mOnClickListener);
        mUVCCameraView5.setOnClickListener(mOnClickListener);
        mUVCCameraView6.setOnClickListener(mOnClickListener);

        mUSBMonitor = new USBMonitor(this, mOnDeviceConnectListener);
    }

    @Override
    protected void onStart() {
        super.onStart();
        mUSBMonitor.register();

        synchronized (mSync) {
            if (mUVCCamera1 != null) {
                mUVCCamera1.startPreview();
            }
            if (mUVCCamera2 != null) {
                mUVCCamera2.startPreview();
            }
            if (mUVCCamera3 != null) {
                mUVCCamera3.startPreview();
            }
            if (mUVCCamera4 != null) {
                mUVCCamera4.startPreview();
            }
            if (mUVCCamera5 != null) {
                mUVCCamera5.startPreview();
            }
            if (mUVCCamera6 != null) {
                mUVCCamera6.startPreview();
            }
        }

    }

    @Override
    protected void onStop() {
        synchronized (mSync) {
            if (mUVCCamera1 != null) {
                mUVCCamera1.stopPreview();
            }
            if (mUVCCamera2 != null) {
                mUVCCamera2.stopPreview();
            }
            if (mUVCCamera3 != null) {
                mUVCCamera3.stopPreview();
            }
            if (mUVCCamera4 != null) {
                mUVCCamera4.stopPreview();
            }
            if (mUVCCamera5 != null) {
                mUVCCamera5.stopPreview();
            }
            if (mUVCCamera6 != null) {
                mUVCCamera6.stopPreview();
            }
            if (mUSBMonitor != null) {
                mUSBMonitor.unregister();
            }
        }

        super.onStop();
    }

    @Override
    protected void onDestroy() {
        synchronized (mSync) {
            releaseCamera(2);
            if (mToast != null) {
                mToast.cancel();
                mToast = null;
            }
            if (mUSBMonitor != null) {
                mUSBMonitor.destroy();
                mUSBMonitor = null;
            }
        }

        mUVCCameraView1 = null;
        mUVCCameraView2 = null;
        mUVCCameraView3 = null;
        mUVCCameraView4 = null;
        mUVCCameraView5 = null;
        mUVCCameraView6 = null;

        super.onDestroy();
    }

    /**
     * @param type 从1到6，释放想对应的控件，0：释放所有
     */
    private synchronized void releaseCamera(int type) {
        synchronized (mSync) {

            switch (type) {
                case 0:
                    releaseCameraTemp(mUVCCamera1, mPreviewSurface1);
                    releaseCameraTemp(mUVCCamera2, mPreviewSurface2);
                    releaseCameraTemp(mUVCCamera3, mPreviewSurface3);
                    releaseCameraTemp(mUVCCamera4, mPreviewSurface4);
                    releaseCameraTemp(mUVCCamera5, mPreviewSurface5);
                    releaseCameraTemp(mUVCCamera6, mPreviewSurface6);
                    break;
                case 1:
                    releaseCameraTemp(mUVCCamera1, mPreviewSurface1);
                    break;
                case 2:
                    releaseCameraTemp(mUVCCamera2, mPreviewSurface2);
                    break;
                case 3:
                    releaseCameraTemp(mUVCCamera3, mPreviewSurface3);
                    break;
                case 4:
                    releaseCameraTemp(mUVCCamera4, mPreviewSurface4);
                    break;
                case 5:
                    releaseCameraTemp(mUVCCamera5, mPreviewSurface5);
                    break;
                case 6:
                    releaseCameraTemp(mUVCCamera6, mPreviewSurface6);
                    break;
            }
        }
    }

    private void releaseCameraTemp(UVCCamera camera, Surface surface) {
        if (camera != null) {
            try {
                camera.setStatusCallback(null);
                camera.setButtonCallback(null);
                camera.close();
                camera.destroy();
            } catch (final Exception e) {
                //
            }
            camera = null;
        }
        if (surface != null) {
            surface.release();
            surface = null;
        }
    }

    private final OnClickListener mOnClickListener = new OnClickListener() {
        @Override
        public void onClick(final View view) {
            switch (view.getId()) {
                case R.id.camera_view_1:
                    type = 1;
                    mOnClickListenerTemp(mUVCCamera1);
                    break;
                case R.id.camera_view_2:
                    type = 2;
                    mOnClickListenerTemp(mUVCCamera2);
                    break;
                case R.id.camera_view_3:
                    type = 3;
                    mOnClickListenerTemp(mUVCCamera3);
                    break;
                case R.id.camera_view_4:
                    type = 4;
                    mOnClickListenerTemp(mUVCCamera4);
                    break;
                case R.id.camera_view_5:
                    type = 5;
                    mOnClickListenerTemp(mUVCCamera5);
                    break;
                case R.id.camera_view_6:
                    type = 6;
                    mOnClickListenerTemp(mUVCCamera6);
                    break;

            }
        }
    };

    private void mOnClickListenerTemp(UVCCamera camera) {
        if (camera == null) {
            CameraDialog.showDialog(MainActivity.this);
        } else {
            releaseCamera(type);
        }
    }


    private final OnDeviceConnectListener mOnDeviceConnectListener = new OnDeviceConnectListener() {
        @Override
        public void onAttach(final UsbDevice device) {
            if (DEBUG) Log.v(TAG, "onAttach:" + device);
            Toast.makeText(MainActivity.this, "USB_DEVICE_ATTACHED", Toast.LENGTH_SHORT).show();
        }

        @Override
        public void onConnect(final UsbDevice device, final UsbControlBlock ctrlBlock, final boolean createNew) {
            if (DEBUG) Log.v(TAG, "onConnect:" + device);
            if (list.contains(ctrlBlock.getDeviceName())) {
                return;
            } else {
                list.add(ctrlBlock.getDeviceName());
            }
            releaseCamera(type);
            queueEvent(new Runnable() {
                @Override
                public void run() {
                    final UVCCamera camera = new UVCCamera();
                    camera.open(ctrlBlock);
                    camera.setStatusCallback(new IStatusCallback() {
                        @Override
                        public void onStatus(final int statusClass, final int event, final int selector,
                                             final int statusAttribute, final ByteBuffer data) {
                            runOnUiThread(new Runnable() {
                                @Override
                                public void run() {
                                    final Toast toast = Toast.makeText(MainActivity.this, "onStatus(statusClass=" + statusClass
                                            + "; " +
                                            "event=" + event + "; " +
                                            "selector=" + selector + "; " +
                                            "statusAttribute=" + statusAttribute + "; " +
                                            "data=...)", Toast.LENGTH_SHORT);
                                    synchronized (mSync) {
                                        if (mToast != null) {
                                            mToast.cancel();
                                        }
                                        toast.show();
                                        mToast = toast;
                                    }
                                }
                            });
                        }
                    });
                    camera.setButtonCallback(new IButtonCallback() {
                        @Override
                        public void onButton(final int button, final int state) {
                            runOnUiThread(new Runnable() {
                                @Override
                                public void run() {
                                    final Toast toast = Toast.makeText(MainActivity.this, "onButton(button=" + button + "; " +
                                            "state=" + state + ")", Toast.LENGTH_SHORT);
                                    synchronized (mSync) {
                                        if (mToast != null) {
                                            mToast.cancel();
                                        }
                                        mToast = toast;
                                        toast.show();
                                    }
                                }
                            });
                        }
                    });
//					camera.setPreviewTexture(camera.getSurfaceTexture());
                    camera.setFrameCallback(new IFrameCallback() {
                        @Override
                        public void onFrame(ByteBuffer frame) {

                        }
                    },UVCCamera.PIXEL_FORMAT_NV21);
                    try {
                        camera.setPreviewSize(UVCCamera.DEFAULT_PREVIEW_WIDTH, UVCCamera.DEFAULT_PREVIEW_HEIGHT, UVCCamera.FRAME_FORMAT_MJPEG, 0.5f);
                    } catch (final IllegalArgumentException e) {
                        // fallback to YUV mode
                        try {
                            camera.setPreviewSize(UVCCamera.DEFAULT_PREVIEW_WIDTH, UVCCamera.DEFAULT_PREVIEW_HEIGHT, UVCCamera.DEFAULT_PREVIEW_MODE, 1.0f);
                        } catch (final IllegalArgumentException e1) {
                            camera.destroy();
                            return;
                        }
                    }

                    switch (type) {
                        case 1:
                            onConnectTemp(mPreviewSurface1, mUVCCameraView1, camera, mUVCCamera1);
                            break;
                        case 2:
                            onConnectTemp(mPreviewSurface2, mUVCCameraView2, camera, mUVCCamera2);
                            break;
                        case 3:
                            onConnectTemp(mPreviewSurface3, mUVCCameraView3, camera, mUVCCamera3);
                            break;
                        case 4:
                            onConnectTemp(mPreviewSurface4, mUVCCameraView4, camera, mUVCCamera4);
                            break;
                        case 5:
                            onConnectTemp(mPreviewSurface5, mUVCCameraView5, camera, mUVCCamera5);
                            break;
                        case 6:
                            onConnectTemp(mPreviewSurface6, mUVCCameraView6, camera, mUVCCamera6);
                            break;

                    }

                }
            }, 0);
        }

        @Override
        public void onDisconnect(final UsbDevice device, final UsbControlBlock ctrlBlock) {
            if (DEBUG) Log.v(TAG, "onDisconnect:" + device);
            releaseCamera(2);
        }

        @Override
        public void onDettach(final UsbDevice device) {
            if (DEBUG) Log.v(TAG, "onDettach:" + device);
            Toast.makeText(MainActivity.this, "USB_DEVICE_DETACHED", Toast.LENGTH_SHORT).show();
        }

        @Override
        public void onCancel(final UsbDevice device) {
            if (DEBUG) Log.v(TAG, "onCancel:");
        }
    };


    @SuppressLint("NewApi")
    private void onConnectTemp(Surface surface, SimpleUVCCameraTextureView uvcCameraTextureView, UVCCamera camera, UVCCamera cameraR) {
        if (surface != null) {
            surface.release();
            surface = null;
        }
        final SurfaceTexture st = uvcCameraTextureView.getSurfaceTexture();
        if (st != null) {
            surface = new Surface(st);
            camera.setPreviewDisplay(surface);
//						camera.setFrameCallback(mIFrameCallback, UVCCamera.PIXEL_FORMAT_RGB565/*UVCCamera.PIXEL_FORMAT_NV21*/);
            camera.startPreview();
        }
        synchronized (mSync) {
            cameraR = camera;
        }
    }

    /**
     * to access from CameraDialog
     *
     * @return
     */
    @Override
    public USBMonitor getUSBMonitor() {
        return mUSBMonitor;
    }

    @Override
    public void onDialogResult(boolean canceled) {
    }

}
